﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace AG.Data
{
    public class AGMapStore
    {
        /// <summary>
        /// 保存地图信息
        /// </summary>
        /// <param name="project"></param>
        /// <param name="map"></param>
        public void SaveMap(string mapsFolder, AGMap map)
        {
            if (!Directory.Exists(mapsFolder))
            {
                Directory.CreateDirectory(mapsFolder);
            }

            string mapFilePath = Path.Combine(mapsFolder, string.Format("{0:d4}.map", map.Id));

            FileStream stream = null;
            if (File.Exists(mapFilePath))
            {
                stream = File.OpenWrite(mapFilePath);
            }
            else
            {
                stream = File.Create(mapFilePath);
            }

            StreamWriter writer = new StreamWriter(stream);

            #region #tiles
            writer.WriteLine("#tiles");
            writer.WriteLine("--id");
            writer.WriteLine(map.Id);
            writer.WriteLine("--version");
            writer.WriteLine("2");
            writer.WriteLine("--name");
            writer.WriteLine(map.Name);
            writer.WriteLine("--row");
            writer.WriteLine(map.Row);
            writer.WriteLine("--col");
            writer.WriteLine(map.Col);
            writer.WriteLine("--terrain");
            for (ushort rowIndex = 0; rowIndex < map.Row; rowIndex++)
            {
                for (ushort colIndex = 0; colIndex < map.Col; colIndex++)
                {
                    AGMapTile tile = map.GetTile(rowIndex, colIndex);
                    writer.Write("{0},", tile.TerrainId);
                }
                writer.WriteLine();
            }

            writer.WriteLine("--tile id");
            for (ushort rowIndex = 0; rowIndex < map.Row; rowIndex++)
            {
                for (ushort colIndex = 0; colIndex < map.Col; colIndex++)
                {
                    AGMapTile tile = map.GetTile(rowIndex, colIndex);
                    writer.Write("{0},", Convert.ToString(tile.TileId, 16));
                }
                writer.WriteLine();
            }

            writer.WriteLine("--tile index");
            for (ushort rowIndex = 0; rowIndex < map.Row; rowIndex++)
            {
                for (ushort colIndex = 0; colIndex < map.Col; colIndex++)
                {
                    AGMapTile tile = map.GetTile(rowIndex, colIndex);
                    writer.Write("{0},", Convert.ToString(tile.TileIndex, 16));
                }
                writer.WriteLine();
            }

            writer.WriteLine("--tile block");
            for (ushort rowIndex = 0; rowIndex < map.Row; rowIndex++)
            {
                for (ushort colIndex = 0; colIndex < map.Col; colIndex++)
                {
                    AGMapTile tile = map.GetTile(rowIndex, colIndex);
                    if (tile.IsBlock)
                    {
                        writer.Write("1,");
                    }
                    else
                    {
                        writer.Write("0,");
                    }
                }
                writer.WriteLine();
            }
            #endregion

            #region #objects
            writer.WriteLine("#objects");
            writer.WriteLine("--objecttype,playerid,objectid,unitid,pos-row,pos-col,action,direction,caption");
            for (int index = 0; index < map.ObjectList.Count; index++)
            {
                AGMapObject mapObj = map.ObjectList[index];
                writer.Write("{0},{1},{2},{3},{4},{5},{6},{7},{8}",
                    mapObj.CategoryId,
                    mapObj.PlayerId,
                    mapObj.Id,
                    mapObj.UnitId,
                    mapObj.PosRow, 
                    mapObj.PosCol, 
                    mapObj.ActionId,
                    mapObj.DirectionId,
                    mapObj.Caption);
                writer.WriteLine();
            }
            #endregion

            #region #switchpoints
            writer.WriteLine("#switchpoints");
            writer.WriteLine("--sp-id,range-start-row,rangecol,range-end-row,range-end-col,targetmapid,targetmapcation,targetrow,targetcol");
            for (int index = 0; index < map.SwitchPoints.Count; index++)
            {
                AGMapSwitchPoint sp = map.SwitchPoints[index];
                writer.Write("{0},{1},{2},{3},{4},{5},{6},{7},{8}",
                    sp.Id,
                    sp.Range.X,
                    sp.Range.Y,
                    sp.Range.Right,
                    sp.Range.Bottom,
                    sp.TargetMapId,
                    sp.TargetMapCaption,
                    sp.TargetPosRow,
                    sp.TargetPosCol);
                writer.WriteLine();
            }
            #endregion

            writer.Close();
            stream.Close();
        }

        public AGMap LoadMap(string mapFilePath)
        {
            AGMap map = new AGMap();

            using (FileStream stream = File.OpenRead(mapFilePath))
            {
                using (StreamReader reader = new StreamReader(stream))
                {
                    int segment = 0;
                    int step = 0;
                    string lineText = reader.ReadLine();
                    while (lineText != null)
                    {
                        if (lineText == "#tiles")
                        {
                            segment = 0;
                            step = 0;
                        }
                        else if (lineText == "#objects")
                        {
                            segment = 1;
                            step = 0;
                        }
                        else if (lineText == "#switchpoints")
                        {
                            segment = 2;
                            step = 0;
                        }
                        else if (!lineText.StartsWith("--"))
                        {
                            if (segment == 0)
                            {
                                if (step == 0)
                                {
                                    // id
                                    map.Id = Convert.ToUInt16(lineText);
                                }
                                else if (step == 1)
                                {
                                    // version
                                }
                                else if (step == 2)
                                {
                                    // name
                                    map.Name = lineText;
                                }
                                else if (step == 3)
                                {
                                    // row
                                    map.Row = Convert.ToUInt16(lineText);
                                }
                                else if (step == 4)
                                {
                                    // col;
                                    map.Col = Convert.ToUInt16(lineText);
                                    map.Tiles = new AGMapTile[map.Row * map.Col];
                                }
                                else if (step > 4 && step < 5 + map.Row)
                                {
                                    // terrain
                                    int row = step - 5;
                                    string[] arr = lineText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                    for (int col = 0; col < arr.Length; col++)
                                    {
                                        AGMapTile cell = new AGMapTile();
                                        cell.PosRow = (ushort)row;
                                        cell.PosCol = (ushort)col;
                                        cell.TerrainId = Convert.ToByte(arr[col], 16);
                                        map.Tiles[row * map.Col + col] = cell;
                                    }
                                }
                                else if (step > 4 + map.Row && step < 5 + 2 * map.Row)
                                {
                                    // tile id
                                    int row = step - (5 + map.Row);
                                    string[] arr = lineText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                    for (int col = 0; col < arr.Length; col++)
                                    {
                                        AGMapTile cell = map.Tiles[row * map.Col + col];
                                        cell.TileId = Convert.ToByte(arr[col], 16);
                                    }
                                }
                                else if (step > 4 + 2 * map.Row && step < 5 + 3 * map.Row)
                                {
                                    // tile index
                                    int row = step - (5 + 2 * map.Row);
                                    string[] arr = lineText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                    for (int col = 0; col < arr.Length; col++)
                                    {
                                        AGMapTile cell = map.Tiles[row * map.Col + col];
                                        cell.TileIndex = Convert.ToByte(arr[col], 16);
                                    }
                                }
                                else if (step > 4 + 3 * map.Row && step < 5 + 4 * map.Row)
                                {
                                    // tile block
                                    int row = step - (5 + 3 * map.Row);
                                    string[] arr = lineText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                    for (int col = 0; col < arr.Length; col++)
                                    {
                                        AGMapTile cell = map.Tiles[row * map.Col + col];
                                        if (arr[col] == "1")
                                        {
                                            cell.IsBlock = true;
                                        }
                                        else
                                        {
                                            cell.IsBlock = false;
                                        }
                                    }
                                }
                            }
                            else if (segment == 1)
                            {
                                // objects
                                // --objecttype,playerid,objectid,unitid,pos-row,pos-col,action,direction,caption
                                string[] objectArr = lineText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                AGMapObject mapObject = new AGMapObject();
                                mapObject.CategoryId = (byte)Convert.ToInt32(objectArr[0]);
                                mapObject.PlayerId = (uint)Convert.ToInt32(objectArr[1]);
                                mapObject.Id = (uint)Convert.ToInt32(objectArr[2]);
                                mapObject.UnitId = (ushort)Convert.ToInt32(objectArr[3]);
                                mapObject.PosRow = (ushort)Convert.ToInt32(objectArr[4]);
                                mapObject.PosCol = (ushort)Convert.ToInt32(objectArr[5]);
                                mapObject.ActionId = (ushort)Convert.ToInt32(objectArr[6]);
                                mapObject.DirectionId = (ushort)Convert.ToInt32(objectArr[7]);
                                mapObject.Caption = objectArr[8];
                                map.ObjectList.Add(mapObject);
                            }
                            else if (segment == 2)
                            {
                                //switch points
                                //--sp-id,range-start-row,rangecol,range-end-row,range-end-col,targetmapid,targetmapcation,targetrow,targetcol
                                string[] spArr = lineText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                AGMapSwitchPoint sp = new AGMapSwitchPoint();
                                sp.Id = (ushort)Convert.ToInt32(spArr[0]);
                                sp.Range = new System.Drawing.Rectangle(Convert.ToInt32(spArr[1]),
                                    Convert.ToInt32(spArr[2]),
                                    Convert.ToInt32(spArr[3]) - Convert.ToInt32(spArr[1]),
                                    Convert.ToInt32(spArr[4]) - Convert.ToInt32(spArr[2]));
                                sp.TargetMapId = (ushort)Convert.ToInt32(spArr[5]);
                                sp.TargetMapCaption = spArr[6];
                                sp.TargetPosRow = (ushort)Convert.ToInt32(spArr[7]);
                                sp.TargetPosCol = (ushort)Convert.ToInt32(spArr[8]);
                                map.SwitchPoints.Add(sp);
                            }
                            step++;
                        }


                        lineText = reader.ReadLine();
                    }
                }
            }
            map.ValidateMaxObjectId();
            return map;
        }

        /// <summary>
        /// 加载地图
        /// </summary>
        /// <param name="project"></param>
        /// <param name="mapRef"></param>
        /// <returns></returns>
        public AGMap LoadMap(string mapFolder, ushort mapId)
        {
            string mapFilePath = Path.Combine(mapFolder, string.Format("{0:d4}.map", mapId));
            if (!File.Exists(mapFilePath))
            {
                // 文件不存在
                return null;
            }

            return LoadMap(mapFilePath);
        }
    }
}
